<?php

namespace App\Common;

use EasySwoole\ORM\DbManager;
use EasySwoole\Http\Request;
use EasySwoole\EasySwoole\ServerManager;

use App\Model\Setting\Setting as AdminSetting;

/**
 * @description: 工具类
 * @param {*}
 * @return {*}
 */
class Tools
{
    /**
     * @description: 分页
     * @param int $page 页码
     * @param array $datas 数据
     * @param int $total 数量总量
     * @param int $limit 每页数量
     * @param array $param 前端查询参数
     * @return {*}
     */
    public static function page($page, $datas, $total, $limit, $param = [])
    {
        $showPage = 5;
        unset($param['page']);
        $lastPage  = ceil($total / $limit);
        return [
            'page'      => $page,
            'datas'     => $datas,
            'total'     => $total,
            'limit'     => $limit,
            'last_page' => $lastPage,
            'query'     => http_build_query($param),
            'pageRange' => static::getPageRange($lastPage, $showPage, $page),
        ];
    }

    /**
     * @description: 获取分页范围
     * @param int $lastPage 最后一页页码
     * @param int $showPage 展示页码
     * @param int $page 当前页码
     * @return {*}
     */
    protected static function getPageRange($lastPage, $showPage, $page)
    {
        $pageRange = range(1, $lastPage > 5 ? 5 : $lastPage);
        if ($lastPage > $showPage) {
            $last = $lastPage - $page;
            if ($page > $showPage && $last > 3) {
                $pageRange = [1, '...', $page - 1, $page, $page + 1, '...', $lastPage];
            } elseif ($last <= 3) {
                $pageRange = [1, '...', $lastPage - 2, $lastPage - 1, $lastPage];
            } else {
                $pageRange[] = '...';
                $pageRange[] = $lastPage;
            }
        }
        return $pageRange;
    }

    /**
     * @description: 返回json数据
     * @param {*} $response
     * @param int $code 状态码
     * @param array $data 数据
     * @param string $msg 描述
     * @return {*}
     */
    public static function json($response, $code, array $data = [], string $msg = '')
    {
        $response->withHeader('Content-Type', 'application/json;charset=utf-8');
        if (is_array($code)) {
            $response->write(json_encode($code));
        } else {
            $response->write(json_encode(['code' => $code, 'result' => $data, 'msg' => $msg]));
        }
    }

    /**
     * @description: 递归数据树
     * @param array $data 
     * @param int $pid 上级id
     * @param string $pid_name 上级字段名
     * @param int $level 层级
     * @param bool $force 强制重置静态变量
     * @return {*}
     */
    public static function recursiveTree($data, $pid = 0, $level = 0, $pid_name = 'parent_id', $force = true)
    {
        static $new = [];
        if ($force) {
            $new = [];
        }
        foreach ($data as $key => $val) {
            if ($val[$pid_name] == $pid) {
                unset($data[$key]);
                if ($level > 0) {
                    $val['name'] = '|' . str_repeat('--', $level) . $val['name'];
                }
                $new[] = $val;
                static::recursiveTree($data, $val['id'], $level + 1, $pid_name, false);
            }
        }
        return $new;
    }

    /**
     * @description: 递归数据
     * @param array $data 
     * @param int $pid 上级id
     * @param string $pid_name 上级字段名
     * @return {*}
     */
    public static function recursiveChild($data, $pid = 0, $pid_name = 'parent_id')
    {
        $new = [];
        foreach ($data as $key => $val) {
            if ($val[$pid_name] == $pid) {
                unset($data[$key]);
                $val['child'] = static::recursiveTree($data, $val['id'], $pid_name);
                $new[] = $val;
            }
        }
        return $new;
    }

    /**
     * @description 判断数组中是否包含指定键且值不为空
     * @param array $param 前端数据
     * @param string $field 查询键名
     * @return bool
     */
    public static function hasValue($param, $field)
    {
        return isset($param[$field]) && (!empty($param[$field]) || $param[$field] == '0')
                ? true 
                : false;
    }

    /**
     * @description: 查询条件数据处理
     * @param array $where 查询条件
     * @param string $op 查询表达式
     * @param string $field 查询字段名
     * @param array $data 查询数据
     * @return {*}
     */
    public static function conditionData(&$where, $op, $field, ...$data)
    {
        switch ($op) {
            case 'like':
                $query = ['%' . $data[0] . '%', $op];
                break;
            case 'between':
                $query = [$data, $op];
                break;
            default:
                $query = [$data[0], $op];
        }
        $where[$field] = $query;
    }

    /**
     * @description: 拼接查询条件
     * @param array $where 查询条件
     * @param array $param 前端数据
     * @param string $field1 查询键名
     * @param string $field2 前端数据键名
     * @param string $op 查询表达式
     * @return {*}
     */
    public static function conditionQuery(&$where, $param, $field1, $field2, $op)
    {
        if (self::hasValue($param, $field2)) {
            self::conditionData($where, $op, $field1, $param[$field2]);
        }
    }


    /**
     * @description: 时间查询条件
     * @param array $where 查询条件
     * @param array $param 前端数据
     * @param string $field1 查询开始时间字段名
     * @param string $field2 查询结束时间字段名
     * @param string $field 查询字段名
     * @return {*}
     */
    public static function conditionTime(&$where, $param, $field1, $field2, $field)
    {
        if (self::hasValue($param, $field1) && self::hasValue($param, $field2)) {
            self::conditionData($where, 'between', $field, $param[$field1], $param[$field2]);
        } elseif (self::hasValue($param, $field1)) {
            self::conditionData($where, '>=', $field, $param[$field1]);
        } elseif (self::hasValue($param, $field2)) {
            self::conditionData($where, '<=', $field, $param[$field2]);
        }
    }

    /**
     * 获取用户的真实IP
     * @param Request $request 请求对象
     * @param string $headerName 代理服务器传递的标头名称
     * @return string
     */
    public static function clientRealIP($request, $headerName = 'x-real-ip')
    {
        $server = ServerManager::getInstance()->getSwooleServer();
        $client = $server->getClientInfo($request->getSwooleRequest()->fd);
        $clientAddress = $client['remote_ip'];
        $xri = $request->getHeader($headerName);
        $xff = $request->getHeader('x-forwarded-for');
        if ($clientAddress === '127.0.0.1') {
            if (!empty($xri)) {  // 如果有 xri 则判定为前端有 NGINX 等代理
                $clientAddress = $xri[0];
            } elseif (!empty($xff)) {  // 如果不存在 xri 则继续判断 xff
                $list = explode(',', $xff[0]);
                if (isset($list[0])) $clientAddress = $list[0];
            }
        }
        return $clientAddress;
    }

    /**
     * @description: 获取批量更新sql
     * @param array $data 数据
     * @param string $tableNmae 表名
     * @param string $key 更新依据主键
     * @param int $limit 每条语句的数据条数
     * @return {*}
     */
    public static function batchUpdateSql(array $data, string $tableNmae, string $key = 'id' , int $limit = 2000)
    {
        $keys  = array_keys($data[0]);
        $keys  = array_diff($keys, [$key]);
        $datas = array_chunk($data, $limit);
        $sqls  = [];
        foreach ($datas as $val) {
            $ids    = [];
            $fields = [];
            $sql    = 'UPDATE ' . $tableNmae . ' ';
            foreach ($val as $v) {
                foreach ($keys as $mkey) {
                    if ($v[$mkey]) {
                        $fields[$mkey][] = sprintf("WHEN %d THEN '%s' ", $v[$key], $v[$mkey]);
                    }
                }
                $ids[] = $v[$key];
            }
            if ($fields) {
                foreach ($fields as $field => $subsql) {
                    $sql .= 'SET ' . $field . ' = CASE ' . $key . ' ' . implode(' ', $subsql) . 'END ';
                }
                $sql   .= ' WHERE ' . $key . ' IN (' . implode(',', $ids) .')';
                $sqls[] = $sql;
            }
        }
        return $sqls;
    }

    /**
     * @description: 获取setting配置
     * @param {*}
     * @return {*}
     */
    public static function getSetting()
    {
        $file = EASYSWOOLE_ROOT. '/Temp/setting';
        if (is_file($file)) {
            return json_decode(file_get_contents($file), true);
        } else {
            static::setSetting();
            return static::getSetting();
        }
    }

    /**
     * @description: 设置setting配置缓存
     * @param {*}
     * @return {*}
     */
    public static function setSetting()
    {
        $data = DbManager::getInstance()->invoke(function ($client) {
            $model = AdminSetting::invoke($client);
            $data  = $model->all()->toArray();
            return $data;
        });
        $result = [];
        foreach ($data as $val) {
            $result[$val['skey']] = $val['vals'];
        }
        $file = EASYSWOOLE_ROOT. '/Temp/setting';
        file_put_contents($file, json_encode($result ,JSON_UNESCAPED_UNICODE));
    }
}